/* * Copyright (c) 2021 BlackWalnut Labs., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "ohos_init.h"
#include "cmsis_os2.h"

#include "iot_watchdog.h"
#include "iot_io.h"
#include "iot_i2c.h"
#include "iot_errno.h"

#include "st25dv.h"
#include "nfc04a1_nfctag.h"
#include "lib_wrapper.h"
#include "tagtype5_wrapper.h"
#include "lib_NDEF.h"
#include "lib_NDEF_URI.h"

const uint8_t I2C_PORT_IDX = 0;
const uint32_t I2C_BAUDRATE = 400000;
extern uint8_t NDEF_Buffer[];
sRecordInfo_t RecordStruct;
sURI_Info url;
const char uri_write_message[] = "blackwalnut.tech";  // Uri message to write in the tag
const char uri_write_protocol[] = URI_ID_0x04_STRING; // Uri protocol to write in the tag

int32_t st25dv_init(void)
{
    // Initial I2C
    IoTI2cInit(I2C_PORT_IDX, I2C_BAUDRATE);
    IoTIoSetFunc(IOT_IO_NAME_10, IOT_IO_FUNC_10_I2C0_SCL);
    IoTIoSetFunc(IOT_IO_NAME_9, IOT_IO_FUNC_9_I2C0_SDA);

    return NFCTAG_OK;
}

int32_t st25dv_deinit(void)
{
    IoTI2cDeinit(I2C_PORT_IDX);
    return NFCTAG_OK;
}

uint32_t st25dv_gettick(void)
{
    return osKernelGetTickCount();
}

int32_t st25dv_isready(const uint8_t device_addr, const uint32_t trials)
{
    uint32_t ret = IOT_FAILURE;
    uint32_t count = 0;
    const static uint8_t p_data = 0;
    while ((count++ < trials) && ret)
    {
        ret = IoTI2cWrite(I2C_PORT_IDX, device_addr, &p_data, 1);
    }
    return ret == IOT_SUCCESS ? NFCTAG_OK : NFCTAG_ERROR;
}

int32_t st25dv_i2c_write(uint16_t device_addr, uint16_t mem_addr, const uint8_t *p_data, uint16_t size)
{
    uint8_t *send_data = NULL;
    send_data = malloc(size + 2);
    if (send_data == NULL)
    {
        return NFCTAG_ERROR;
    }

    send_data[0] = (uint8_t)(mem_addr >> 8);
    send_data[1] = (uint8_t)(mem_addr & 0xFF);
    memcpy(send_data + 2, p_data, size);

    uint32_t retval = IoTI2cWrite(I2C_PORT_IDX, device_addr, send_data, 2 + size);
    free(send_data);

    return retval == IOT_SUCCESS ? NFCTAG_OK : NFCTAG_ERROR;
}

int32_t st25dv_i2c_read(uint16_t device_addr, uint16_t mem_addr, uint8_t *p_data, uint16_t size)
{
    uint8_t mem_add_fix[2] = {(uint8_t)(mem_addr >> 8), (uint8_t)(mem_addr & 0xFF)};
    uint32_t retval = IoTI2cWriteRead(I2C_PORT_IDX, device_addr, mem_add_fix, 2, p_data, size);

    return retval == IOT_SUCCESS ? NFCTAG_OK : NFCTAG_ERROR;
}

static void ST25DV04K_GETURI(void *args)
{
    (void)(args);
    ST25DV_IO_t IO;
    IO.Init = st25dv_init;
    IO.DeInit = st25dv_deinit;
    IO.GetTick = st25dv_gettick;
    IO.IsReady = st25dv_isready;
    IO.Write = st25dv_i2c_write;
    IO.Read = st25dv_i2c_read;

    int32_t status = NFC04A1_NFCTAG_Init(0, &IO);
    if (status != NFCTAG_OK)
    {
        printf("NFC Init fail: %d\r\n", status);
    }

    status = NFC04A1_NFCTAG_ResetMBEN_Dyn(0);
    if (status != NFCTAG_OK)
    {
        printf("ResetMBEN_Dyn fail: %d\r\n", status);
    }

    status = NfcTag_SelectProtocol(NFCTAG_TYPE5);
    if (status != NFCTAG_OK)
    {
        printf("NfcTag_SelectProtocol fail: %d\r\n", status);
    }

    if (NfcType5_NDEFDetection() != NDEF_OK)
    {
        CCFileStruct.MagicNumber = NFCT5_MAGICNUMBER_E1_CCFILE;
        CCFileStruct.Version = NFCT5_VERSION_V1_0;
        CCFileStruct.MemorySize = (ST25DV_MAX_SIZE / 8) & 0xFF;
        CCFileStruct.TT5Tag = 0x05;
        /* Init of the Type Tag 5 component (M24LR) */
        status = NfcType5_TT5Init();
        if (status != NDEF_OK)
        {
            printf("NfcType5_TT5 Init fail: %d\r\n", status);
        }
    }

    strcpy(url.protocol, uri_write_protocol);
    strcpy(url.URI_Message, uri_write_message);
    strcpy(url.Information, "");

    status = NDEF_WriteURI(&url);
    if (status != NDEF_OK)
    {
        printf("NDEF_WriteURI fail: %d\r\n", status);
    }
    else
    {
        printf("NDEF Write URI Success (uri_write_protocol: %s, uri_write_message: %s).\r\n", uri_write_protocol, uri_write_message);
    }

    while (1)
    {
        memset(NDEF_Buffer, '\0', 20);      /* Avoid printing useless characters */
        memset(url.Information, '\0', 400); /*Clear url buffer before reading*/

        status = NDEF_ReadNDEF(NDEF_Buffer);

        if (status == RESULTOK)
        {
            status = NDEF_IdentifyNDEF(&RecordStruct, NDEF_Buffer);

            if (status == RESULTOK && RecordStruct.TypeLength != 0)
            {
                if (NDEF_ReadURI(&RecordStruct, &url) == RESULTOK) /*---if URI read passed---*/
                {
                    printf("\r\n\r\n--------------------\r\n*****URI Reader*****\r\n--------------------\r\nURI Information read successfully from the tag: \r\n     URI Information: [%s], \r\n     URI Protocol: [%s] ,  \r\n     URI Message: [%s]",
                           (char *)url.Information, (char *)url.protocol, (char *)url.URI_Message);
                }
            }
        }
        osDelay(1000);
    }
}

static void ST25DV04K_APP(void)
{
    IoTWatchDogDisable();

    osThreadAttr_t attr;

    attr.name = "ST25DV04K_GETURI";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityLow1;

    if (osThreadNew(ST25DV04K_GETURI, NULL, &attr) == NULL)
    {
        printf("[ST25DV04K_GETURI] Falied to create ST25DV04K_GETURI!\n");
    }
}

SYS_RUN(ST25DV04K_APP);